package com.zoe.onelink.mybatis.method;

import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import com.baomidou.mybatisplus.core.toolkit.sql.SqlScriptUtils;
import com.google.common.base.Strings;
import com.zoe.onelink.annotation.mybatis.SearchField;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * SearchList 搜索
 * </p>
 *
 * @author fanliwen
 * @since 2/17/2020
 */
@SuppressWarnings("Duplicates")
public class SearchList extends AbstractMethod {
  @Override
  public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
    SqlMethod sqlMethod = SqlMethod.SEARCH_LIST;
    Map<String, Field> fldMap = ReflectionKit.getFieldMap(modelClass);
    String sqlSearch = "";
    List<String> likeList = new ArrayList<String>();
    for (TableFieldInfo fld : tableInfo.getFieldList()) {
      Field field = fldMap.get(fld.getProperty());
      SearchField sf = field.getAnnotation(SearchField.class);
      if (sf != null) {
        String like = fld.getColumn() + " like '%${query}%'";
        likeList.add(like);
      }
    }

    if (likeList.size() > 0) {
      String likeStr = String.join(" or ", likeList);
      sqlSearch = "(" + likeStr + ")";
    }

    String sql = String.format(sqlMethod.getSql(),
            sqlSelectColumns(tableInfo, true),
            tableInfo.getTableName(),
            sqlWhereEntityWrapper(true, tableInfo, sqlSearch),
            sqlComment());
    SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
    return this.addSelectMappedStatementForTable(mapperClass, sqlMethod.getMethod(), sqlSource, tableInfo);
  }

  protected String sqlWhereEntityWrapper(boolean newLine, TableInfo table, String search) {
    String sqlScript = "";
    if (table.isLogicDelete()) {
      sqlScript += table.getAllSqlWhere(true, true, WRAPPER_ENTITY_DOT);
      sqlScript = SqlScriptUtils.convertIf(sqlScript, String.format("%s != null", WRAPPER_ENTITY),
              true);
      sqlScript += (NEWLINE + table.getLogicDeleteSql(true, true) + NEWLINE);
      String normalSqlScript = SqlScriptUtils.convertIf(String.format("AND ${%s}", WRAPPER_SQLSEGMENT),
              String.format("%s != null and %s != '' and %s", WRAPPER_SQLSEGMENT, WRAPPER_SQLSEGMENT,
                      WRAPPER_NONEMPTYOFNORMAL), true);
      normalSqlScript += NEWLINE;
      normalSqlScript += SqlScriptUtils.convertIf(String.format(" ${%s}", WRAPPER_SQLSEGMENT),
              String.format("%s != null and %s != '' and %s", WRAPPER_SQLSEGMENT, WRAPPER_SQLSEGMENT,
                      WRAPPER_EMPTYOFNORMAL), true);
      sqlScript += normalSqlScript;
      sqlScript = SqlScriptUtils.convertChoose(String.format("%s != null", WRAPPER), sqlScript,
              table.getLogicDeleteSql(false, true));

      if (!Strings.isNullOrEmpty(search)) {
        sqlScript = search + sqlScript;
      }

      sqlScript = SqlScriptUtils.convertWhere(sqlScript);
      return newLine ? NEWLINE + sqlScript : sqlScript;
    } else {
      if (!Strings.isNullOrEmpty(search)) {
        sqlScript = search +
                "\n<if test=\"ew != null and ew.entity != null or (ew.sqlSegment != null and ew.sqlSegment != '' and ew.emptyOfWhere)\">\n" +
                " and " +
                "</if>\n";
      }
      sqlScript += table.getAllSqlWhere(false, true, WRAPPER_ENTITY_DOT);
      sqlScript = SqlScriptUtils.convertIf(sqlScript, String.format("%s != null", WRAPPER_ENTITY), true);
      sqlScript += NEWLINE;
      sqlScript += SqlScriptUtils.convertIf(String.format(SqlScriptUtils.convertIf(" AND", String.format("%s and %s", WRAPPER_NONEMPTYOFENTITY, WRAPPER_NONEMPTYOFNORMAL), false) + " ${%s}", WRAPPER_SQLSEGMENT),
              String.format("%s != null and %s != '' and %s", WRAPPER_SQLSEGMENT, WRAPPER_SQLSEGMENT,
                      WRAPPER_NONEMPTYOFWHERE), true);

      sqlScript = SqlScriptUtils.convertWhere(sqlScript) + NEWLINE;
      sqlScript += SqlScriptUtils.convertIf(String.format(" ${%s}", WRAPPER_SQLSEGMENT),
              String.format("%s != null and %s != '' and %s", WRAPPER_SQLSEGMENT, WRAPPER_SQLSEGMENT,
                      WRAPPER_EMPTYOFWHERE), true);
      if (Strings.isNullOrEmpty(search)) {
        sqlScript = SqlScriptUtils.convertIf(sqlScript, String.format("%s != null", WRAPPER), true);
      }
      return newLine ? NEWLINE + sqlScript : sqlScript;
    }
  }
}
